import { Injectable, Logger } from '@nestjs/common';
import { Client } from '@larksuiteoapi/node-sdk';
import axios from 'axios';
import dayjs, { Dayjs } from 'dayjs';
import * as fs from 'fs';
import * as path from 'path';

export interface FeishuConfig {
  appId: string;
  appSecret: string;
  baseId: string;
  tableId: string;
}

export interface AppInfo {
  app_id: string;
  name: string;
  revision: number;
  revision_diff: number;
  app_token: string;
  token?: string; // 添加可选的token字段
  create_time: number;
  update_time: number;
  folder_token: string;
}

export interface AppList {
  items: AppInfo[];
  page_token?: string;
  has_more: boolean;
  total?: number;
}

export interface TableInfo {
  table_id: string;
  name: string;
  revision: number;
  revision_diff: number;
}

export interface TableList {
  items: TableInfo[];
  page_token?: string;
  has_more: boolean;
  total?: number;
}

export interface TokenResponse {
  code: number;
  msg: string;
  tenant_access_token: string;
  expire: number;
}

export interface FeishuApiResponse<T> {
  code: number;
  msg: string;
  data: T;
}

export interface TableRecord {
  fields: Record<string, unknown>;
  id: string;
  record_id: string;
}

export interface TableRecordList {
  items: TableRecord[];
  page_token?: string;
  has_more: boolean;
  total?: number;
}

export interface TableField {
  field_name: string;
  id: string;
  type: number;
  property?: Record<string, unknown>;
}

export interface TableFieldList {
  items: TableField[];
}

export interface TableView {
  id: string;
  name: string;
  type: string;
  property?: Record<string, unknown>;
}

export interface TableViewList {
  items: TableView[];
}

@Injectable()
export class FeishuService {
  private readonly logger = new Logger(FeishuService.name);
  private client: Client;
  private config: FeishuConfig = {
    appId: process.env.FEISHU_APP_ID || '',
    appSecret: process.env.FEISHU_APP_SECRET || '',
    baseId: process.env.FEISHU_BASE_ID || 'NQZzbPR7RaT6VZs2rgOcGmW5nN0',
    tableId: process.env.FEISHU_TABLE_ID || 'tblKK3B3uA876rMG',
  };
  private token: string = '';
  private tokenExpireTime: number = 0;

  // 缓存数据
  private cachedTableData: TableRecordList | null = null;
  private cacheTime: number = 0;
  private readonly CACHE_EXPIRY = 3600000; // 缓存过期时间，1小时
  private isCacheValid = false;

  // 文件缓存相关
  private readonly CACHE_DIR = 'cache';
  private readonly CACHE_FILE = 'feishu_data.json';
  private readonly CACHE_FILE_PATH = path.join(
    process.cwd(),
    this.CACHE_DIR,
    this.CACHE_FILE,
  );

  constructor() {
    this.client = new Client({
      appId: this.config.appId,
      appSecret: this.config.appSecret,
    });
    void this.initClient();
    // 确保缓存目录存在
    this.ensureCacheDir();
  }

  /**
   * 根据日期动态设置 baseId 和 tableId
   * @param date 日期字符串，格式为 YYYY-MM-DD
   */
  async setConfigByDate(date?: string): Promise<boolean> {
    try {
      // 如果没有提供日期，则使用当前日期
      let targetDate: Dayjs;
      if (date) {
        // 验证日期格式是否有效
        // 安全地处理日期字符串
        let parsedDate: Dayjs;
        try {
          parsedDate = dayjs(date);
          // 使用isValid()方法检查日期是否有效
          if (!parsedDate.isValid()) {
            this.logger.warn(`提供的日期 ${date} 格式无效，使用当前日期`);
            targetDate = dayjs();
          } else {
            targetDate = parsedDate;
          }
        } catch (parseError) {
          // 如果解析日期时出错，使用当前日期
          const errorMessage =
            parseError instanceof Error ? parseError.message : '未知错误';
          this.logger.warn(
            `解析日期 ${date} 时出错: ${errorMessage}，使用当前日期`,
          );
          targetDate = dayjs();
        }
      } else {
        targetDate = dayjs();
      }
      const formattedDate = targetDate.format('YYYY-MM-DD');

      this.logger.log(`根据日期 ${formattedDate} 设置多维表格配置`);

      // 获取多维表格列表
      const appList = await this.getAppList();
      if (!appList.success || !appList.data) {
        this.logger.error(`获取多维表格列表失败: ${appList.message}`);
        return false;
      }

      // 查找包含日期的多维表格
      const targetApp = appList.data.items.find((app) => {
        // 确保app.name是字符串类型并且不为null或undefined
        if (typeof app.name === 'string') {
          return app.name.includes(formattedDate);
        }
        return false;
      });

      if (!targetApp) {
        this.logger.warn(
          `未找到日期为 ${formattedDate} 的多维表格，使用默认配置`,
        );
        return false;
      }

      // 设置 baseId
      this.config.baseId = targetApp.app_token;
      this.logger.log(`已设置 baseId: ${this.config.baseId}`);

      // 获取表格列表
      const tableList = await this.getTableList(this.config.baseId);
      if (!tableList.success || !tableList.data) {
        this.logger.error(`获取表格列表失败: ${tableList.message}`);
        return false;
      }

      // 获取第一个表格作为目标表格
      if (tableList.data.items.length > 0) {
        this.config.tableId = tableList.data.items[0].table_id;
        this.logger.log(`已设置 tableId: ${this.config.tableId}`);
        return true;
      } else {
        this.logger.warn(
          `多维表格 ${this.config.baseId} 中没有表格，使用默认配置`,
        );
        return false;
      }
    } catch (error) {
      // 安全地处理错误对象
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      this.logger.error(`设置多维表格配置出错: ${errorMessage}`, error);
      return false;
    }
  }

  /**
   * 获取多维表格列表
   * @param pageSize 每页记录数，默认100
   * @param pageToken 分页标记，默认为空
   */
  async getAppList(
    pageSize: number = 100,
    pageToken?: string,
  ): Promise<{
    success: boolean;
    data: AppList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = 'https://open.feishu.cn/open-apis/bitable/v1/apps';

      const params: Record<string, string | number> = {
        page_size: pageSize,
      };

      if (pageToken) {
        params.page_token = pageToken;
      }

      const response = await axios.get<FeishuApiResponse<AppList>>(url, {
        params,
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json; charset=utf-8',
        },
      });

      if (response.data.code === 0) {
        return {
          success: true,
          data: response.data.data,
          message: '获取多维表格列表成功',
        };
      } else {
        this.logger.error(
          `获取多维表格列表失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `获取多维表格列表失败: ${response.data.msg}`,
        };
      }
    } catch (error) {
      // 安全地处理错误对象
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      this.logger.error('获取多维表格列表出错', error);
      return {
        success: false,
        data: null,
        message: `获取多维表格列表出错: ${errorMessage}`,
      };
    }
  }

  /**
   * 获取表格列表
   * @param baseId 多维表格ID
   * @param pageSize 每页记录数，默认100
   * @param pageToken 分页标记，默认为空
   */
  async getTableList(
    baseId: string,
    pageSize: number = 100,
    pageToken?: string,
  ): Promise<{
    success: boolean;
    data: TableList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${baseId}/tables`;

      const params: Record<string, string | number> = {
        page_size: pageSize,
      };

      if (pageToken) {
        params.page_token = pageToken;
      }

      const response = await axios.get<FeishuApiResponse<TableList>>(url, {
        params,
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json; charset=utf-8',
        },
      });

      if (response.data.code === 0) {
        return {
          success: true,
          data: response.data.data,
          message: '获取表格列表成功',
        };
      } else {
        this.logger.error(`获取表格列表失败: ${JSON.stringify(response.data)}`);
        return {
          success: false,
          data: null,
          message: `获取表格列表失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('获取表格列表出错', error);
      return {
        success: false,
        data: null,
        message: `获取表格列表出错: ${error.message || '未知错误'}`,
      };
    }
  }

  private async initClient(): Promise<void> {
    if (!this.config.appId || !this.config.appSecret) {
      this.logger.warn(
        '飞书 AppID 或 AppSecret 未配置，部分功能可能无法正常使用',
      );
    }
    await Promise.resolve();
  }

  /**
   * 获取飞书访问令牌
   */
  private async getAccessToken(): Promise<string> {
    // 如果令牌未过期，直接返回
    if (this.token && this.tokenExpireTime > Date.now()) {
      return this.token;
    }

    try {
      const response = await axios.post<TokenResponse>(
        'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
        {
          app_id: this.config.appId,
          app_secret: this.config.appSecret,
        },
      );

      if (response.data.code === 0) {
        this.token = response.data.tenant_access_token;
        // 设置过期时间（提前5分钟过期，以防边界情况）
        this.tokenExpireTime = Date.now() + (response.data.expire - 300) * 1000;
        return this.token;
      } else {
        this.logger.error(
          `获取飞书访问令牌失败: ${JSON.stringify(response.data)}`,
        );
        throw new Error(`获取飞书访问令牌失败: ${response.data.msg}`);
      }
    } catch (error) {
      this.logger.error('获取飞书访问令牌出错', error);
      throw error;
    }
  }

  /**
   * 获取多维表格数据
   * @param viewId 视图ID，默认为空，表示使用默认视图
   * @param pageSize 每页记录数，默认100
   * @param pageToken 分页标记，默认为空
   */
  /**
   * 确保缓存目录存在
   */
  private ensureCacheDir(): void {
    try {
      if (!fs.existsSync(path.join(process.cwd(), this.CACHE_DIR))) {
        fs.mkdirSync(path.join(process.cwd(), this.CACHE_DIR), {
          recursive: true,
        });
        this.logger.log(`创建缓存目录: ${this.CACHE_DIR}`);
      }
    } catch (error) {
      this.logger.error(`创建缓存目录失败: ${error.message}`);
    }
  }

  /**
   * 保存数据到缓存文件
   */
  private saveCacheToFile(): void {
    try {
      if (!this.cachedTableData) {
        return;
      }

      const cacheData = {
        data: this.cachedTableData,
        timestamp: this.cacheTime,
        baseId: this.config.baseId,
        tableId: this.config.tableId,
      };

      fs.writeFileSync(
        this.CACHE_FILE_PATH,
        JSON.stringify(cacheData, null, 2),
        'utf8',
      );
      this.logger.log(`数据已缓存到文件: ${this.CACHE_FILE_PATH}`);
    } catch (error) {
      this.logger.error(`保存缓存文件失败: ${error.message}`);
    }
  }

  /**
   * 从缓存文件加载数据
   */
  private loadCacheFromFile(): boolean {
    try {
      if (!fs.existsSync(this.CACHE_FILE_PATH)) {
        this.logger.log(`缓存文件不存在: ${this.CACHE_FILE_PATH}`);
        return false;
      }

      const fileContent = fs.readFileSync(this.CACHE_FILE_PATH, 'utf8');
      const cacheData = JSON.parse(fileContent);

      if (!cacheData || !cacheData.data || !cacheData.timestamp) {
        this.logger.warn('缓存文件格式无效');
        return false;
      }

      // 检查缓存是否过期
      if (Date.now() - cacheData.timestamp > this.CACHE_EXPIRY) {
        this.logger.log('缓存文件已过期');
        return false;
      }

      // 设置缓存数据
      this.cachedTableData = cacheData.data;
      this.cacheTime = cacheData.timestamp;
      this.isCacheValid = true;

      // 如果缓存中有 baseId 和 tableId，也一并设置
      if (cacheData.baseId && cacheData.tableId) {
        this.config.baseId = cacheData.baseId;
        this.config.tableId = cacheData.tableId;
        this.logger.log(
          `从缓存文件加载 baseId: ${this.config.baseId}, tableId: ${this.config.tableId}`,
        );
      }

      this.logger.log(
        `成功从文件加载缓存数据，包含 ${this.cachedTableData?.items.length} 条记录`,
      );
      return true;
    } catch (error) {
      this.logger.error(`加载缓存文件失败: ${error.message}`);
      return false;
    }
  }

  /**
   * 获取表格数据（使用缓存）
   */
  async getTableRecords(
    viewId?: string,
    pageSize: number = 100,
    pageToken?: string,
  ): Promise<{
    success: boolean;
    data: TableRecordList | null;
    message: string;
  }> {
    // 先尝试从内存缓存获取
    if (
      this.isCacheValid &&
      this.cachedTableData &&
      Date.now() - this.cacheTime < this.CACHE_EXPIRY
    ) {
      this.logger.log('使用内存缓存数据');
      return {
        success: true,
        data: this.cachedTableData,
        message: '使用内存缓存数据获取成功',
      };
    }

    // 如果内存缓存无效，尝试从文件缓存加载
    if (this.loadCacheFromFile()) {
      this.logger.log('使用文件缓存数据');
      return {
        success: true,
        data: this.cachedTableData,
        message: '使用文件缓存数据获取成功',
      };
    }

    // 缓存无效或过期，直接获取最新数据
    return this.fetchTableRecords(viewId, pageSize, pageToken);
  }

  /**
   * 获取指定文件夹下的文档列表
   * @param folderId 文件夹ID
   * @param date 日期字符串，格式为 YYYY-MM-DD
   */
  async getFolderDocuments(
    folderId: string,
    date?: string,
  ): Promise<{
    success: boolean;
    data: AppList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      // 如果没有提供日期，则使用当前日期
      const targetDate: Dayjs = date ? dayjs(date) : dayjs();
      const formattedDate = targetDate.format('YYYY-MM-DD');

      this.logger.log(`获取文件夹 ${folderId} 下的 ${formattedDate} 文档`);

      // 获取文件夹下的文档列表
      const url = `https://open.feishu.cn/open-apis/drive/v1/files`;

      const response = await axios.get<FeishuApiResponse<any>>(url, {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json; charset=utf-8',
        },
        params: {
          folder_token: folderId,
          order_by: 'EditedTime',
          direction: 'DESC',
          page_size: 100,
        },
      });

      if (response.data.code === 0) {
        // 过滤出包含当前日期的文档
        const files = response.data.data.files || [];

        const filteredItems = files.filter(
          (item: { name?: string; type?: string }) => {
            return (
              item.name &&
              item.name.includes(formattedDate) &&
              item.type === 'bitable'
            );
          },
        );

        this.logger.log(`找到 ${filteredItems.length} 个匹配的文档`);
        filteredItems.forEach((item, index) => {
          this.logger.log(
            `文档 ${index + 1}: ${item.name}, token: ${item.token}`,
          );
        });

        return {
          success: true,
          data: { items: filteredItems, has_more: false },
          message: `成功获取文件夹文档，找到 ${filteredItems.length} 个匹配的文档`,
        };
      } else {
        this.logger.error(
          `获取文件夹文档失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `获取文件夹文档失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('获取文件夹文档出错', error);
      return {
        success: false,
        data: null,
        message: `获取文件夹文档出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 更新缓存数据
   */
  async updateCachedData(): Promise<boolean> {
    try {
      this.logger.log('开始更新缓存数据');

      // 获取当前日期
      const currentDate = dayjs().format('YYYY-MM-DD');

      // 指定的文件夹ID
      const folderId = 'IDnvfCYlLl4XNOda7v7cpXjznud';

      // 获取指定文件夹下当前日期的文档
      const folderResult = await this.getFolderDocuments(folderId, currentDate);

      if (
        !folderResult.success ||
        !folderResult.data ||
        folderResult.data.items.length === 0
      ) {
        this.logger.error(`未找到日期为 ${currentDate} 的文档`);
        return false;
      }

      // 获取第一个匹配的文档
      const targetDoc = folderResult.data.items[0];

      // 设置 baseId
      this.config.baseId = targetDoc.token || '';
      this.logger.log(`已设置 baseId: ${this.config.baseId}`);

      // 获取表格列表
      const tableList = await this.getTableList(this.config.baseId);

      if (
        !tableList.success ||
        !tableList.data ||
        tableList.data.items.length === 0
      ) {
        this.logger.error('未找到表格');
        return false;
      }

      // 设置 tableId为第一个表格
      this.config.tableId = tableList.data.items[0].table_id;
      this.logger.log(`已设置 tableId: ${this.config.tableId}`);

      // 获取表格数据并缓存
      const result = await this.fetchTableRecords();

      if (result.success && result.data) {
        this.cachedTableData = result.data;
        this.cacheTime = Date.now();
        this.isCacheValid = true;

        // 保存到文件缓存
        this.saveCacheToFile();

        this.logger.log(`成功缓存 ${result.data.items.length} 条记录`);
        return true;
      } else {
        this.logger.error(`获取表格数据失败: ${result.message}`);
        return false;
      }
    } catch (error: any) {
      this.logger.error('更新缓存数据出错', error);
      return false;
    }
  }

  /**
   * 获取表格数据（不使用缓存）
   */
  async fetchTableRecords(
    viewId?: string,
    pageSize: number = 100,
    pageToken?: string,
  ): Promise<{
    success: boolean;
    data: TableRecordList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${this.config.baseId}/tables/${this.config.tableId}/records`;

      const params: Record<string, string | number> = {
        page_size: pageSize,
      };

      if (viewId) {
        params.view_id = viewId;
      }

      if (pageToken) {
        params.page_token = pageToken;
      }

      const response = await axios.get<FeishuApiResponse<TableRecordList>>(
        url,
        {
          params,
          headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json; charset=utf-8',
          },
        },
      );

      if (response.data.code === 0) {
        return {
          success: true,
          data: response.data.data,
          message: '获取数据成功',
        };
      } else {
        this.logger.error(
          `获取多维表格数据失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `获取数据失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('获取多维表格数据出错', error);
      return {
        success: false,
        data: null,
        message: `获取数据出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 获取多维表格元数据（字段信息）
   */
  async getTableMetadata(): Promise<{
    success: boolean;
    data: TableFieldList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${this.config.baseId}/tables/${this.config.tableId}/fields`;

      const response = await axios.get<FeishuApiResponse<any>>(url, {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json; charset=utf-8',
        },
      });

      if (response.data.code === 0) {
        return {
          success: true,
          data: response.data.data,
          message: '获取字段信息成功',
        };
      } else {
        this.logger.error(
          `获取多维表格字段信息失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `获取字段信息失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('获取多维表格字段信息出错', error);
      return {
        success: false,
        data: null,
        message: `获取字段信息出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 获取多维表格视图列表
   */
  async getTableViews(): Promise<{
    success: boolean;
    data: TableViewList | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${this.config.baseId}/tables/${this.config.tableId}/views`;

      const response = await axios.get<FeishuApiResponse<any>>(url, {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json; charset=utf-8',
        },
      });

      if (response.data.code === 0) {
        return {
          success: true,
          data: response.data.data,
          message: '获取视图列表成功',
        };
      } else {
        this.logger.error(
          `获取多维表格视图列表失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `获取视图列表失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('获取多维表格视图列表出错', error);
      return {
        success: false,
        data: null,
        message: `获取视图列表出错: ${error.message || '未知错误'}`,
      };
    }
  }

  /**
   * 更新多维表格记录
   * @param recordId 记录ID
   * @param fields 要更新的字段数据
   */
  async updateTableRecord(
    recordId: string,
    fields: Record<string, unknown>,
  ): Promise<{
    success: boolean;
    data: TableRecord | null;
    message: string;
  }> {
    try {
      const token = await this.getAccessToken();

      const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/${this.config.baseId}/tables/${this.config.tableId}/records/${recordId}`;

      const response = await axios.put<
        FeishuApiResponse<{ record: TableRecord }>
      >(
        url,
        {
          fields,
        },
        {
          headers: {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json; charset=utf-8',
          },
        },
      );

      if (response.data.code === 0) {
        // 更新成功后，如果缓存有效，也更新缓存中的数据
        if (this.isCacheValid && this.cachedTableData) {
          const recordIndex = this.cachedTableData.items.findIndex(
            (item) => item.record_id === recordId,
          );
          if (recordIndex !== -1) {
            // 更新缓存中的记录
            this.cachedTableData.items[recordIndex].fields = {
              ...this.cachedTableData.items[recordIndex].fields,
              ...fields,
            };
            // 保存更新后的缓存到文件
            this.saveCacheToFile();
            this.logger.log(`已更新缓存中的记录: ${recordId}`);
          }
        }

        return {
          success: true,
          data: response.data.data.record,
          message: '更新记录成功',
        };
      } else {
        this.logger.error(
          `更新多维表格记录失败: ${JSON.stringify(response.data)}`,
        );
        return {
          success: false,
          data: null,
          message: `更新记录失败: ${response.data.msg}`,
        };
      }
    } catch (error: any) {
      this.logger.error('更新多维表格记录出错', error);
      return {
        success: false,
        data: null,
        message: `更新记录出错: ${error.message || '未知错误'}`,
      };
    }
  }
}
